﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Vowei.Services.SharePoint;
using System.Xml.XPath;
using Vowei.Test.Library;
using System.Xml;
using System.IO;
using System.Diagnostics;
using Vowei.Core.Models;
using Vowei.Data.Helpers;
using Vowei.Data;
using Vowei.Data.Models;
using System.Globalization;

namespace vowei.test
{
    [TestClass]
    public class TicketServiceTest : TestBase
    {
        private const string ProvideId = "{7765B84F-6D32-4d31-B28E-6BC615D2F187}";

        private int GetListBasicTestSelectDescendantsHelper(XPathNavigator nav, XmlNamespaceManager mgr, string attr)
        {
            return nav.Select(string.Format("b:Fields/b:Field[@Name='{0}']", attr), mgr).Count;
        }

        [TestMethod]
        public void GetListBasicTest()
        {
            var service = new TicketService(VoweiContext, new ServiceMockHttpContext(), Setting.DefaultFormUser);
            // var service = new TicketService(VoweiContext, new ServiceMockHttpContext());
            var node = service.GetList(ProvideId);

            Assert.IsNotNull(node);
            var nav = node.CreateNavigator();
            var mgr = new XmlNamespaceManager(node.OwnerDocument.NameTable);
            mgr.AddNamespace("b", nav.NamespaceURI);
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "ID"));
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "Modified"));
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "Created"));
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "Priority"));
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "Status"));
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "PercentComplete"));
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "AssignedTo"));
            Assert.AreEqual(1, GetListBasicTestSelectDescendantsHelper(nav, mgr, "StartDate"));

            Assert.IsNotNull(nav.Select("b:RegionalSettings", mgr));
        }

        [TestMethod]
        public void CreateRequirementTest()
        {
            var service = new TicketService(VoweiContext, new ServiceMockHttpContext(), Setting.DefaultFormUser);
            var requirement = new Requirement()
            {
                Title = "这是一个测试需求",
                BelongsToMilestoneId = GetDefaultProject(VoweiContext).ID
            };
            service.CreateRequirement(requirement);
        }

        private void GetListItemChangesSinceTokenBasicTestVerifyHelper(
            XPathNavigator nav, XmlNamespaceManager mgr, Task task)
        {
            // var iter = nav.Select(string.Format("rs:data/z:row[@ows_ID='{0}']", task.ID.ToString("D")), mgr);
            var iter = nav.Select(string.Format("rs:data/z:row[@ows_ID='{0}']", task.IdForOws), mgr);
            Assert.IsNotNull(iter);
            Assert.AreEqual(1, iter.Count);

            iter.MoveNext();
            var title = iter.Current.GetAttribute("ows_Title", string.Empty);
            Assert.IsNotNull(title);
            Assert.AreEqual(task.Title, title);

            var assignedTo = iter.Current.GetAttribute("ows_AssignedTo", string.Empty);
            Assert.AreEqual(task.AssignedTo, assignedTo);

            var percentage = Single.Parse(iter.Current.GetAttribute("ows_PercentComplete", string.Empty));
            Assert.IsTrue((task.Progress - percentage) <= 0.00001);

            var status = iter.Current.GetAttribute("ows_Status", string.Empty);
            if (task.Status != null)
                Assert.AreEqual(task.Status, status);
            else
                Assert.AreEqual(string.Empty, status);

            var body = iter.Current.GetAttribute("ows_Body", string.Empty);
            if (task.Description != null)
                Assert.AreEqual(task.Description, body);
            else
                Assert.AreEqual(string.Empty, body);
        }

        [TestMethod]
        public void GetListItemChangesSinceTokenBasicTest()
        {
            var service = new TicketService(VoweiContext, new ServiceMockHttpContext(), Setting.DefaultFormUser);
            // var service = new TicketService(VoweiContext, new ServiceMockHttpContext());
            var project = CreateProjectHelper("GetListItemChangesSinceTokenBasicTest");
            ImportTestDataToProject(project, VoweiContext);

            var viewFields = new XmlDocument();
            viewFields.LoadXml("<ViewFields Properties=\"TRUE\" xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\"><FieldRef Name=\"ID\" /><FieldRef Name=\"ReplicationID\" /><FieldRef Name=\"Attachments\" /><FieldRef Name=\"owshiddenversion\" /><FieldRef Name=\"Created\" /><FieldRef Name=\"Modified\" /><FieldRef Name=\"vti_versionhistory\" /><FieldRef Name=\"ContentTypeId\" /><FieldRef Name=\"Title\" /><FieldRef Name=\"Body\" /><FieldRef Name=\"EmailBody\" /><FieldRef Name=\"Priority\" /><FieldRef Name=\"Status\" /><FieldRef Name=\"PercentComplete\" /><FieldRef Name=\"StartDate\" /><FieldRef Name=\"DueDate\" /><FieldRef Name=\"FormURN\" /><FieldRef Name=\"ContactLinkName\" /><FieldRef Name=\"Categories\" /><FieldRef Name=\"DateComplete\" /><FieldRef Name=\"ActualWork\" /><FieldRef Name=\"TotalWork\" /><FieldRef Name=\"Role\" /><FieldRef Name=\"LastUpdate\" /><FieldRef Name=\"Mileage\" /><FieldRef Name=\"BillingInformation\" /><FieldRef Name=\"TaskCompanies\" /><FieldRef Name=\"AssignedTo\" /><FieldRef Name=\"Editor\" /><FieldRef Name=\"MetaInfo\" /><FieldRef Name=\"PermMask\" /></ViewFields>");

            var queryOptions = new XmlDocument();
            queryOptions.LoadXml("<QueryOptions xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\"><ViewAttributes Scope=\"RecursiveAll\" /><DateInUtc>TRUE</DateInUtc><IncludePermissions>FALSE</IncludePermissions><IncludeAttachmentUrls>TRUE</IncludeAttachmentUrls><IncludeAttachmentVersion>TRUE</IncludeAttachmentVersion><ExpandUserField>TRUE</ExpandUserField><MeetingInstanceID>-1</MeetingInstanceID><OptimizeLookups>TRUE</OptimizeLookups></QueryOptions>");

            var node = service.GetListItemChangesSinceToken(project.ID.ToString("D"), string.Empty,
                null,
                viewFields,
                "100",
                queryOptions,
                null,
                null);

            Assert.IsNotNull(node);

            var mgr = CreateNsManager(node);
            var nav = node.CreateNavigator();
            var mytasks = project.AllTasks(VoweiContext).My(Setting.DefaultFormUser);
            foreach (var task in mytasks)
                GetListItemChangesSinceTokenBasicTestVerifyHelper(nav, mgr, task);

            var countIter = nav.Select("rs:data", mgr);
            countIter.MoveNext();
            var count = countIter.Current.GetAttribute("ItemCount", string.Empty);
            Assert.AreEqual(mytasks.Count().ToString(), count);

            countIter = nav.Select("rs:data/z:row", mgr);
            Assert.AreEqual(mytasks.Count(), countIter.Count);
        }

        [TestMethod]
        public void GetListItemChangesSinceTokenChangedTimeTest()
        {
            var service = new TicketService(VoweiContext, new ServiceMockHttpContext(), Setting.DefaultFormUser);
            // var service = new TicketService(VoweiContext, new ServiceMockHttpContext());
            var project = CreateProjectHelper("GetListItemChangesSinceTokenChangedTimeTest");
            ImportTestDataToProject(project, VoweiContext);
            var modifiedDate = DateTime.Now + TimeSpan.FromDays(1);
            
            var task = project.AllTasks(VoweiContext).First();
            VoweiContext.TicketStatusManager.Close(task);
            task.Description = "<p>Test html description</p>";
            task.LastModified = modifiedDate;
            VoweiContext.SaveChanges();

            var viewFields = new XmlDocument();
            viewFields.LoadXml("<ViewFields Properties=\"TRUE\" xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\"><FieldRef Name=\"ID\" /><FieldRef Name=\"ReplicationID\" /><FieldRef Name=\"Attachments\" /><FieldRef Name=\"owshiddenversion\" /><FieldRef Name=\"Created\" /><FieldRef Name=\"Modified\" /><FieldRef Name=\"vti_versionhistory\" /><FieldRef Name=\"ContentTypeId\" /><FieldRef Name=\"Title\" /><FieldRef Name=\"Body\" /><FieldRef Name=\"EmailBody\" /><FieldRef Name=\"Priority\" /><FieldRef Name=\"Status\" /><FieldRef Name=\"PercentComplete\" /><FieldRef Name=\"StartDate\" /><FieldRef Name=\"DueDate\" /><FieldRef Name=\"FormURN\" /><FieldRef Name=\"ContactLinkName\" /><FieldRef Name=\"Categories\" /><FieldRef Name=\"DateComplete\" /><FieldRef Name=\"ActualWork\" /><FieldRef Name=\"TotalWork\" /><FieldRef Name=\"Role\" /><FieldRef Name=\"LastUpdate\" /><FieldRef Name=\"Mileage\" /><FieldRef Name=\"BillingInformation\" /><FieldRef Name=\"TaskCompanies\" /><FieldRef Name=\"AssignedTo\" /><FieldRef Name=\"Editor\" /><FieldRef Name=\"MetaInfo\" /><FieldRef Name=\"PermMask\" /></ViewFields>");

            var queryOptions = new XmlDocument();
            queryOptions.LoadXml("<QueryOptions xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\"><ViewAttributes Scope=\"RecursiveAll\" /><DateInUtc>TRUE</DateInUtc><IncludePermissions>FALSE</IncludePermissions><IncludeAttachmentUrls>TRUE</IncludeAttachmentUrls><IncludeAttachmentVersion>TRUE</IncludeAttachmentVersion><ExpandUserField>TRUE</ExpandUserField><MeetingInstanceID>-1</MeetingInstanceID><OptimizeLookups>TRUE</OptimizeLookups></QueryOptions>");

            var changeToken = string.Format("1;3;{0};{1};1", project.ID.ToString("D"), modifiedDate.Date.Ticks.ToString());

            var node = service.GetListItemChangesSinceToken(project.ID.ToString("D"), string.Empty,
                null,
                viewFields,
                "100",
                queryOptions,
                changeToken,
                null);

            Assert.IsNotNull(node);
            var mgr = CreateNsManager(node);
            var nav = node.CreateNavigator();
            GetListItemChangesSinceTokenBasicTestVerifyHelper(nav, mgr, task);

            var countIter = nav.Select("rs:data", mgr);
            countIter.MoveNext();
            var count = countIter.Current.GetAttribute("ItemCount", string.Empty);
            Assert.AreEqual("1", count);
        }

        [TestMethod]
        public void UpdateListItemsBasicTest()
        {
            var service = new TicketService(VoweiContext, new ServiceMockHttpContext(), Setting.DefaultFormUser);
            // var service = new TicketService(VoweiContext, new ServiceMockHttpContext());
            var project = CreateProjectHelper("UpdateListItemsBasicTest");
            ImportTestDataToProject(project, VoweiContext);
            var listName = project.ID.ToString("D");
            var tasks = project.AllTasks(VoweiContext).Take(4);

            foreach (var task in tasks)
                VoweiContext.TicketStatusManager.Close(task);

            var node = ConvertTasksToUpdateItemsNode(tasks, false);
            service.UpdateListItems(listName, node);

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                foreach (var task in tasks)
                {
                    var actual = context.Tasks.Find(task.ID);
                    Assert.AreEqual(task.Status, actual.Status);
                    Assert.AreEqual(task.Progress, actual.Progress);
                }
            }

            Assert.Inconclusive("需要验证修改纪录是否已经跟踪到了！");
        }

        [TestMethod]
        public void UpdateListItemsAddNewTaskBasicTest()
        {
            var service = new TicketService(VoweiContext, new ServiceMockHttpContext(), Setting.DefaultFormUser);
            //var service = new TicketService(VoweiContext, new ServiceMockHttpContext());
            var project = CreateProjectHelper("UpdateListItemsAddNewTaskBasicTest");
            ImportTestDataToProject(project, VoweiContext);
            var listName = project.ID.ToString("D");
            var task = CreateTaskHelper("UpdateListItemsAddNewTaskBasicTest", project);
            task.AssignedTo = Setting.DefaultFormUser.Email;
            task.StartDate = DateTime.Now;
            task.DueDate = project.DueDate;

            try
            {
                var node = ConvertTasksToUpdateItemsNode(new Task[] { task }, true);
                service.UpdateListItems(listName, node);

                using (var impl = new VoweiContextImpl())
                {
                    var context = new VoweiContext(impl);
                    var actual = context.Tasks.Query.FirstOrDefault(t => t.Title == task.Title);
                    Assert.IsNotNull(actual);
                    Assert.AreEqual(task.Title, actual.Title);
                    Assert.AreEqual(string.Empty, actual.Description);
                    AreDateTimeEquals(task.StartDate, actual.StartDate);
                    AreDateTimeEquals(task.DueDate, actual.DueDate);
                    AreDateTimeEquals(task.ClosedDate, actual.ClosedDate);
                    Assert.AreEqual(task.AssignedTo, actual.AssignedTo);
                    Assert.AreEqual(string.Empty, actual.Status);
                    Assert.AreEqual(task.Progress, actual.Progress);
                }
            }
            finally
            {
                using (var impl = new VoweiContextImpl())
                {
                    foreach (var t in impl.Tasks.Where(t => t.Title == task.Title))
                        impl.Tasks.Remove(t);

                    impl.SaveChanges();
                }
            }

            Assert.Inconclusive("需要验证修改纪录是否已经跟踪到了！");
        }

        private XmlNode ConvertTasksToUpdateItemsNode(IEnumerable<Task> tasks, bool newitem)
        {
            var text = "<Batch OnError=\"Continue\" DateInUtc=\"TRUE\" Properties=\"TRUE\" xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">{0}</Batch>";
            // 0 -> method id
            // 1 -> ID
            // 2 -> Title
            // 3 -> Description
            // 4 -> Priority
            // 5 -> Status
            // 6 -> Progress
            // 7 -> Start Date
            // 8 -> Due Date
            // 9 -> Closed Date
            // 10 -> Assigned To
            // 11 -> Update command
            var template = "<Method ID=\"{0}\" Cmd=\"{11}\">" +
                           "  <Field Name=\"ID\">{1}</Field>" +
                           "  <Field Name=\"owshiddenversion\">0</Field>" +
                           "  <Field Name=\"Title\">{2}</Field>" +
                           "  <Field Name=\"Body\">{3}</Field>" +
                           "  <Field Name=\"Priority\">{4}</Field>" +
                           "  <Field Name=\"Status\">{5}</Field>" +
                           "  <Field Name=\"PercentComplete\">{6}</Field>" +
                           "  <Field Name=\"StartDate\">{7}</Field>" +
                           "  <Field Name=\"DueDate\">{8}</Field>" +
                           "  <Field Name=\"MetaInfo\" Property=\"ContactLinkName\"> </Field>" + 
                           "  <Field Name=\"MetaInfo\" Property=\"Categories\"> </Field>" +
                           "  <Field Name=\"MetaInfo\" Property=\"DateComplete\">{9}</Field>" +
                           "  <Field Name=\"MetaInfo\" Property=\"ActualWork\"> </Field>" +
                           "  <Field Name=\"MetaInfo\" Property=\"TotalWork\"> </Field>" +
                           "  <Field Name=\"MetaInfo\" Property=\"Role\"> </Field>" + 
                           "  <Field Name=\"MetaInfo\" Property=\"LastUpdate\"> </Field>" +
                           "  <Field Name=\"MetaInfo\" Property=\"Mileage\"> </Field>" + 
                           "  <Field Name=\"MetaInfo\" Property=\"BillingInformation\"> </Field>" +
                           "  <Field Name=\"MetaInfo\" Property=\"TaskCompanies\"> </Field>" +
                           "  <Field Name=\"AssignedTo\">{10}</Field>" + 
                           "  <Field Name=\"MetaInfo\" Property=\"vti_versionhistory\">f1c4139f8918f3448484b39c84ce8fc8:1</Field>" +
                           "</Method>";
            var methodId = 0;
            var builder = new StringBuilder();
            foreach (var task in tasks)
            {
                builder.AppendFormat(template, methodId++,
                    newitem ? "New" : task.IdForOws.ToString(),
                    task.Title,
                    task.Description,
                    task.Priority,
                    task.Status,
                    task.Progress,
                    task.StartDate.Value.ToString("u", CultureInfo.InvariantCulture),
                    task.DueDate.Value.ToString("u", CultureInfo.InvariantCulture),
                    task.ClosedDate.HasValue? task.ClosedDate.Value.ToString("u") : null,
                    task.AssignedTo, 
                    newitem ? "New" : "Update");
            }

            text = string.Format(text, builder.ToString());
            var doc = new XmlDocument();
            doc.LoadXml(text);
            return doc.DocumentElement;
        }

        private static XmlNamespaceManager CreateNsManager(XmlNode node)
        {
            var mgr = new XmlNamespaceManager(node.OwnerDocument.NameTable);
            mgr.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
            mgr.AddNamespace("z", "#RowsetSchema");
            mgr.AddNamespace("b", "http://schemas.microsoft.com/sharepoint/soap/");
            return mgr;
        }
    }
}
